
import gtk
import gobject
import pygtk

import re

from ..scheduler import AlarmTime
from ..balancer import BalanceFilter

import resources

class ConfigDialog:
    """Allow the user to set configuration parameters."""

    def __init__(self, gm):
        self.__gm = gm
        self.__to_run = [] # Things to run on successful completion

    def __add_run(self, toRun):
        self.__to_run.append(toRun)


    def run(self):
        d = self.__dialog = gtk.Dialog(title="Configure Balancer")
        self.__dialog.set_modal(True)
        self.__dialog.set_icon_list(*resources.icon_list(resources.BASE_ICON))

        # Create the notebook
        n = self.__notebook = gtk.Notebook()
        d.vbox.pack_start(n)

        self.__add_page_notification()
        self.__add_page_scheduling()

        d.connect("response", self.__signal_response)

        # Add the buttons
        d.add_buttons(gtk.STOCK_OK, gtk.RESPONSE_OK)
        d.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_DELETE_EVENT)

        d.set_default_response(0)

        self.__dialog.show_all()


    def __signal_response(self, dialog, response_id):
        if response_id == gtk.RESPONSE_OK:
            for runnable in self.__to_run:
                runnable()

        if self.__schedule_rows_update:
            self.__update_schedule_rows()

        self.__dialog.destroy()

    def __add_page_notification(self):
        """Add a configuration page dealing with notification"""
        page = gtk.VBox()

        ### Add the email config
        table = gtk.Table(5, 2)

        save = None

        def run_save(widget, ranFlag):
            if not ranFlag[0]:
                self.__add_run(save)
            ranFlag[0] = True

        config = self.__gm.get_email_notification()

        # To
        label = gtk.Label("Send to:")
        table.attach(label, 0, 1, 0, 1)

        to = gtk.Entry()
        if config.has_key('to'):
            to.set_text(config['to'])
        table.attach(to, 1, 2, 0, 1)

        # From
        label = gtk.Label("Send from:")
        table.attach(label, 0, 1, 1, 2)

        fromAddy = gtk.Entry()
        if config.has_key('from'):
            fromAddy.set_text(config['from'])
        table.attach(fromAddy, 1, 2, 1, 2)

        # Server
        label = gtk.Label("SMTP server:")
        table.attach(label, 0, 1, 2, 3)

        server = gtk.Entry()
        if config.has_key('server'):
            server.set_text(config['server'])
        table.attach(server, 1, 2, 2, 3)

        # Server port
        label = gtk.Label("Server port:")
        table.attach(label, 0, 1, 3, 4)

        port = gtk.Entry()
        if config.has_key('port'):
            port.set_text(config['port'])
        table.attach(port, 1, 2, 3, 4)

        # Server password
        label = gtk.Label("Server password:")
        table.attach(label, 0, 1, 4, 5)

        password = gtk.Entry()
        password.set_visibility(False)
        password.set_invisible_char(u"\u2022")
        if config.has_key('password'):
            password.set_text(config['password'])
        table.attach(password, 1, 2, 4, 5)


        flag = [False]
        to.connect("changed", run_save, flag)
        fromAddy.connect("changed", run_save, flag)
        server.connect("changed", run_save, flag)
        port.connect("changed", run_save, flag)
        password.connect("changed", run_save, flag)

        page.pack_start(table)


        ### Add the account config
        listStore = gtk.ListStore(str, str, str, str, str, gobject.TYPE_BOOLEAN, str, gobject.TYPE_BOOLEAN)
        
        filter = self.__gm.get_email_notification_filter()
        old = self.__gm.get_historian().last_run()
        NICKNAME = '<Nickname>'
        for rec in old.get_accounts():
            src_uuid = rec.get_source().get_source_uuid()
            show = not filter.should_remove(src_uuid, rec.get_uuid())

            nick = filter.filtered_name(src_uuid, rec.get_uuid(), NICKNAME)
            has_nick = not nick == NICKNAME

            listStore.append([rec.get_source().get_source_uuid(), rec.get_uuid(), rec.get_name(), rec.get_moniker(), rec.get_balance(), show, nick, has_nick])

        filtered = filter.filter(old)

        tree = gtk.TreeView(listStore)

        txtRender = gtk.CellRendererText()

        # Name column
        col = gtk.TreeViewColumn("Name")
        tree.append_column(col)

        col.pack_start(txtRender, True)
        col.add_attribute(txtRender, 'text', 2)

        # Moniker column
        col = gtk.TreeViewColumn("Account")
        tree.append_column(col)

        col.pack_start(txtRender, True)
        col.add_attribute(txtRender, 'text', 3)

        # Balance column
        col = gtk.TreeViewColumn("Balance")
        tree.append_column(col)

        col.pack_start(txtRender, True)
        col.add_attribute(txtRender, 'text', 4)

        # Include toggle
        renderer = gtk.CellRendererToggle()
        renderer.set_property('activatable', True)
        
        col = gtk.TreeViewColumn("Send")

        col.pack_start(renderer, True)
        col.add_attribute(renderer, "active", 5)
        
        def toggled_cb(cell, path, user_data):
            """Called to change the toggle state of a row in the account config"""
            model, col, ranFlag = user_data
            model[path][col] = not model[path][col]

            if not ranFlag[0]:
                self.__add_run(save)
            ranFlag[0] = True
        
        renderer.connect('toggled', toggled_cb, (listStore, 5, flag))

        tree.append_column(col)

        # Balance column
        txtRender = gtk.CellRendererText()
        col = gtk.TreeViewColumn("Nickname")
        tree.append_column(col)

        col.pack_start(txtRender, True)
        col.add_attribute(txtRender, 'text', 6)
        txtRender.set_property('editable', True)


        def edit_started(cellrenderer, editable, path, ranFlag):
            if not ranFlag[0]:
                self.__add_run(save)
            ranFlag[0] = True

            if isinstance(editable, gtk.Entry):
                if NICKNAME == editable.get_text():
                    editable.set_text("")

        txtRender.connect('editing-started', edit_started, flag)


        def edit_completed(cellrenderertext, path, new_text, store):
            has_nick = True
            if new_text == "":
                new_text = NICKNAME
                has_nick = False

            iter = store.get_iter_from_string(path)
            store.set(iter, 6, new_text)
            store.set(iter, 7, has_nick)
        
        txtRender.connect('edited', edit_completed, listStore)


        def save():
            self.__gm.set_email_notification(
                to.get_text(), server.get_text(), port.get_text(), fromAddy.get_text(), 
                password.get_text()
            )
            
            filter = BalanceFilter()

            i = listStore.get_iter_first()
            while i:
                source_uuid, account_uuid, account_name, show, rename, should_rename \
                        = listStore.get(i, 0, 1, 2, 5, 6, 7)

                print "%s - %s - %s - %s - %s - %s" % (source_uuid, account_uuid, account_name, show, rename, should_rename)

                if not should_rename:
                    rename = None

                if (not show) or should_rename:
                    filter.add_filter(source_uuid, account_uuid, hide=not show, rename=rename)

                i = listStore.iter_next(i)

            print 'save'
            self.__gm.set_email_notification_filter(filter)

        page.pack_start(tree)

        self.__notebook.append_page(page, gtk.Label("Notification"))



    def __index_alarms_by_day(self, alarms):
        """Take an array of alarms, and return a dict, indexed by day."""
        dict = {}

        for alarm in alarms:
            dict[alarm.get_day()] = alarm

        return dict


    def __add_page_scheduling(self):
        """Add a configuration page dealing with deciding when the scrape should run"""
        page = gtk.VBox()

        table = gtk.Table(7, 4)
        alarms = self.__index_alarms_by_day(self.__gm.get_scheduler().get_alarms())
        
        self.__schedule_rows = rows = []
        self.__schedule_rows_update = False

        for i in range(0, 7):
            row = [alarms.has_key(i), 0, 0, i]
            if alarms.has_key(i):
                row[1] = alarms[i].get_hour()
                row[2] = alarms[i].get_minute()

            # Show enabled/disabled
            enabled = "Enabled"
            check = gtk.CheckButton(enabled)
            check.set_active(alarms.has_key(i))

            def e(w, i): 
                rows[i][0] = w.get_active()
                self.__schedule_rows_update = True
            check.connect("toggled", e, i)

            table.attach(check, 0, 1, i, i+1)


            # Show the day
            day = gtk.Label(AlarmTime.DAYS[i])

            table.attach(day, 1, 2, i, i+1)

            # Show the hour
            hour = gtk.Entry(2)
            hour.set_width_chars(2)
            if alarms.has_key(i):
                hour.set_text(str(alarms[i].get_hour()))

            denumPattern = re.compile(r"[^01-9]")
            def h(w, i): 
                w.set_text(denumPattern.sub('', w.get_text()))
                if w.get_text_length() > 0 and int(w.get_text()) > 23:
                    w.set_text("23")
                rows[i][1] = w.get_text()
                self.__schedule_rows_update = True
            hour.connect("changed", h, i)

            table.attach(hour, 2, 3, i, i+1)

            # Show the minutes
            minutes = gtk.Entry(2)
            minutes.set_width_chars(2)
            if alarms.has_key(i):
                minutes.set_text("%s" % alarms[i].get_minute())


            def m(w, i): 
                w.set_text(denumPattern.sub('', w.get_text()))
                if w.get_text_length() > 0 and (int(w.get_text()) > 60):
                    w.set_text("60")
                rows[i][2] = w.get_text()
                self.__schedule_rows_update = True
            minutes.connect("changed", m, i)

            table.attach(minutes, 3, 4, i, i+1)

            rows.append(row)

        page.pack_start(table)

        self.__notebook.append_page(page, gtk.Label("Scheduling"))


    def __update_schedule_rows(self):
        """Update the scheduler with our input."""
        # Create the alarms
        alarms = []

        for row in self.__schedule_rows:
            if row[0]:
                alarms.append(AlarmTime(int(row[3]), int(row[1]), int(row[2])))

        self.__gm.get_scheduler().set_alarms(alarms)
